package main

import (
	"go/ast"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

type oneCtx struct {
	Pkg   string
	Base  string
	Group string
	Regs  []*reg
	Len   int
}

func one(pkg, f, txt string, decls []ast.Decl) {
	lines := strings.Split(txt, "\n")
	_, base := nameval(lines[0], ':')
	_, err := strconv.ParseUint(base, 0, 64)
	if err != nil {
		fdie(f, "bad BaseAddr address '%s': %v", base, err)
	}
	ctx := &oneCtx{
		Pkg:   pkg,
		Base:  base,
		Group: strings.TrimSuffix(filepath.Base(f), ".go"),
	}
	ctx.Regs, ctx.Len = regs(f, lines[1:], decls)
	save(f, oneTmpl, ctx)
}

// PROBLEM: This very elegant approach has one importand drawback. {{.Bits}} has
// many methods defined on it. {{.Reg}}_Load returns {{.Bits}} value (to allow
// compiler type check it when passed to {{.Reg}}_Store). Because {{.Bits}} is
// a number and it is often very useful itself. It can be easly passed, for
// example, to fmt.Prinln function. This causes assignment to interface{} which
// maens that {{.Bits}} typeinfo should be linked to resultant binary. Because
// there is one {{.Bits}} defined for one register and each one has many (8)
// methods there can be significant incrase of of ROM/Flash usage even if some
// registers are accessed only once at startup.
//
// Alternative (multi) approach isn't as flexible as this but it is more general
// (supports multiple instances of peripheral) and defines only two methods on
// {{.Bits}} so ROM/Flash consumption is reduced.
 
const oneText = `package {{.Pkg}}

// DO NOT EDIT THIS FILE. GENERATED BY xgen.

import (
	"bits"
	"mmio"
	"unsafe"
)

{{$rf := .Group}}
func {{$rf}}(n uint) *mmio.U32 {
	return &(*[{{.Len}}]mmio.U32)(unsafe.Pointer(uintptr({{.Base}})))[n]
}
{{range .Regs}}
{{$rfn := print $rf "(" .N ")"}}
type {{.Bits}} uint32

func (m {{.Bits}}) Set()           { {{$rfn}}.SetBits(uint32(m)) }
func (m {{.Bits}}) Clear()         { {{$rfn}}.ClearBits(uint32(m)) }
func (m {{.Bits}}) Load() uint32   { return {{$rfn}}.Bits(uint32(m)) }
func (m {{.Bits}}) Store(b uint32) { {{$rfn}}.StoreBits(uint32(m), b) }
func (m {{.Bits}}) LoadVal() int   { return {{$rfn}}.Field(uint32(m)) }
func (m {{.Bits}}) StoreVal(v int) { {{$rfn}}.SetField(uint32(m), v) }

func {{.Reg}}_Load() {{.Bits}}   { return {{.Bits}}({{$rfn}}.Load()) }
func {{.Reg}}_Store(b {{.Bits}}) { {{$rfn}}.Store(uint32(b)) }

func (b {{.Bits}}) Field(mask {{.Bits}}) int {
	return bits.Field32(uint32(b), uint32(mask))
}
func (mask {{.Bits}}) J(v int) {{.Bits}} {
	return {{.Bits}}(bits.MakeField32(v, uint32(mask)))
}
{{end}}
`

var oneTmpl = template.Must(template.New("one").Parse(oneText))
